package com.pine.dcts.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pine.dcts.common.DctsException;
import com.pine.dcts.common.TaskStatusType;
import com.pine.dcts.entity.JobConfigAttr;
import com.pine.dcts.entity.StepItem;
import com.pine.dcts.entity.StepLink;
import com.pine.dcts.entity.JobInfo;
import com.pine.dcts.mapper.JobConfigAttrMapper;
import com.pine.dcts.mapper.StepItemMapper;
import com.pine.dcts.mapper.StepLinkMapper;
import com.pine.dcts.mapper.JobInfoMapper;
import com.pine.dcts.model.JobVO;
import com.pine.dcts.query.JobQuery;
import com.pine.dcts.service.JobService;
import com.pine.dcts.utils.Base64;
import com.pine.dcts.utils.CopierUtil;
import com.pine.dcts.utils.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service
public class JobServiceImpl extends ServiceImpl<JobInfoMapper, JobInfo> implements JobService {
    @Autowired
    private StepItemMapper entryMapper;
    @Autowired
    private StepLinkMapper jobHopMapper;
    @Autowired
    private JobConfigAttrMapper jobConfigAttrMapper;

    @Override
    public List<JobVO> getList() {
        List<JobVO> list = CopierUtil.copy(this.list(), JobVO.class);
        list.forEach(jobInfo -> {
            LambdaQueryWrapper<StepItem> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(StepItem::getJobId, jobInfo.getId());
            jobInfo.setItems(entryMapper.selectList(wrapper));
            LambdaQueryWrapper<StepLink> wrapper1 = new LambdaQueryWrapper<>();
            wrapper1.eq(StepLink::getJobId, jobInfo.getId());
            jobInfo.setLinks(jobHopMapper.selectList(wrapper1));
        });
        return list;
    }

    @Transactional
    @Override
    public void addJob(JobVO jobVO) {
        if (jobVO.getId() != null) {
            updateJob(jobVO);
            return;
        }
        JobInfo jobInfo = CopierUtil.copy(jobVO, JobInfo.class);
        List<StepItem> entries = jobVO.getItems();
        List<StepLink> jobHops = jobVO.getLinks();
        jobInfo.setStatus(TaskStatusType.NOT_START.getValue());
        this.save(jobInfo);
        entries.forEach(entry -> {
            entry.setJobId(jobInfo.getId());
            //  entry.setId(UUID.randomUUID().toString());
            entry.setConfig(Base64.encode(JSON.toJSONBytes(entry.getAttrs())));

            entryMapper.insert(entry);
        });
        jobHops.forEach(jobHop -> {
            jobHop.setJobId(jobInfo.getId());
            jobHopMapper.insert(jobHop);
        });

        JSONObject config = jobVO.getConfig();
        if (config != null && config.size() > 0) {
            config.forEach((k, v) -> {
                this.jobConfigAttrMapper.insert(new JobConfigAttr(k, JSON.toJSONString(v), jobInfo.getId()));
            });
        }

    }

    @Transactional
    @Override
    public void updateJob(JobVO jobVO) {
        JobInfo oldJob = this.baseMapper.selectById(jobVO.getId());
        if (oldJob.getStatus().equals(TaskStatusType.RUNNING.getValue())) {
            throw new DctsException("job任务运行中，无法更新");
        }
        JobInfo jobInfo = CopierUtil.copy(jobVO, JobInfo.class);
        List<StepItem> entries = jobVO.getItems();
        List<StepLink> jobHops = jobVO.getLinks();
        jobInfo.setUpdateBy(Integer.valueOf(Objects.requireNonNull(SecurityUtils.getUserId())));
        jobInfo.setUpdateTime(new Date());
        this.updateById(jobInfo);
        entries.forEach(entry -> {
            // entry.setJobId(jobInfo.getId());
            entry.setConfig(Base64.encode(JSON.toJSONBytes(entry.getAttrs())));
            entryMapper.updateById(entry);
        });
        jobHops.forEach(jobHop -> {
            jobHop.setJobId(jobInfo.getId());
            jobHopMapper.update(jobHop, new LambdaQueryWrapper<StepLink>());
        });
        LambdaUpdateWrapper<JobConfigAttr> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(JobConfigAttr::getJobId, jobInfo.getId());
        this.jobConfigAttrMapper.delete(wrapper);
        JSONObject config = jobVO.getConfig();
        if (config != null && config.size() > 0) {
            config.forEach((k, v) -> {
                this.jobConfigAttrMapper.insert(new JobConfigAttr(k, JSON.toJSONString(v), jobInfo.getId()));
            });
        }
    }

    @Override
    public void deleteJob(Integer jobId) {
        JobInfo jobInfo = this.getById(jobId);
        if (jobInfo.getStatus() == 1) {
            throw new DctsException("job任务运行中，无法删除");
        }
        this.removeById(jobId);
        LambdaQueryWrapper<StepItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StepItem::getJobId, jobInfo.getId());
        entryMapper.delete(wrapper);
        LambdaQueryWrapper<StepLink> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(StepLink::getJobId, jobInfo.getId());
        jobHopMapper.delete(wrapper1);
    }

    @Override
    public JobVO getJobVOById(Integer jobId) {
        JobInfo jobInfo = this.getById(jobId);
        if (jobInfo == null) {
            throw new DctsException("job信息不存在");
        }
        JobVO jobVO = CopierUtil.copy(jobInfo, JobVO.class);
        LambdaQueryWrapper<StepItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StepItem::getJobId, jobInfo.getId());
        jobVO.setItems(entryMapper.selectList(wrapper));
        LambdaQueryWrapper<StepLink> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(StepLink::getJobId, jobInfo.getId());
        jobVO.setLinks(jobHopMapper.selectList(wrapper1));
        LambdaUpdateWrapper<JobConfigAttr> jobConfigAttrLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        jobConfigAttrLambdaUpdateWrapper.eq(JobConfigAttr::getJobId, jobInfo.getId());
        List<JobConfigAttr> configAttrs = this.jobConfigAttrMapper.selectList(jobConfigAttrLambdaUpdateWrapper);
        JSONObject jsonObject = new JSONObject();
        configAttrs.forEach(ob -> {
            jsonObject.put(ob.getName(), JSON.parseObject(ob.getValue()));
        });
        jobVO.setConfig(jsonObject);
        return jobVO;
    }

    @Override
    public IPage<JobInfo> page(JobQuery query) {
        Page<JobInfo> page = query.getPage();
        LambdaQueryWrapper<JobInfo> wrapper = new LambdaQueryWrapper<>();
        return this.page(page, wrapper);
    }
}
